import { memo, useContext, useMemo } from 'react';
import type { DataType, FieldNames } from '../types';
import RuleNode from './RuleNode';
import RuleItem from './RuleItem';
import { NoopContext, RuleTreeContext, RuleTreePropsContext } from './RuleTreeContext';
import { Button, Space } from 'antd';
import { clsx, invokeFunc, toLevelPath, wrapperCls, getRelationPath, getDeepth } from '../utils';
import DropIndicator from './DropIndicator';
import { addRuleGroup, addRuleItem } from '../utils/model';
import { useOutterComponents, useLocale } from '../utils/hooks';
import { fieldNamesTreeMap } from '../utils/global';

function RuleListCore<T>(props: {
  path: (string | number)[]
  /** 其实就是list的索引，为null是因为root层不存在，做判断使用 */
  name: number | null
  data: T[]
  uid: string;
}) {
  const { localeMap } = useLocale();
  const { prefixCls, FormListContext = NoopContext } = useContext(RuleTreeContext);
  const { Form, FormList } = useOutterComponents();
  const form = Form.useFormInstance();
  const { children, onChange, max, maxDeepth, createRender, disabled, defaultRelationValue, uid } = useContext(RuleTreePropsContext);
  const cls = wrapperCls(prefixCls);
  const { children: ChildrenKey, relation: RelationKey } = fieldNamesTreeMap.get(uid) as Required<FieldNames>;
  const deepth = getDeepth(props.path);
  const levelPath = toLevelPath(props.path);
  const overMaxCount = props.data.length >= (max ?? Infinity);
  const overMaxDeepth = deepth >= (maxDeepth ?? Infinity);


  const addDom = invokeFunc(() => {
    const mergeDisabled = disabled || overMaxCount;
    return (
      <Button
        key={'addDom'}
        disabled={mergeDisabled}
        size="small"
        onClick={() => {
          addRuleItem(form, props.path);
          onChange?.(form.getFieldsValue(true));
        }}
      >{localeMap.addRule}</Button>
    );
  });

  const addGroupDom = invokeFunc(() => {
    const mergeDisabled = disabled || overMaxCount || overMaxDeepth;
    return (
      <Button
        key={'addGroupDom'}
        disabled={mergeDisabled}
        size="small"
        onClick={() => {
          addRuleGroup(form, props.path, ChildrenKey, { [RelationKey]: defaultRelationValue });
          onChange?.(form.getFieldsValue(true));
        }}
      >{localeMap.addRuleGroup}</Button>
    );
  });

  const ctrlDoms = invokeFunc(() => {
    return createRender?.(
      {
        addDom: addDom,
        addGroupDom: addGroupDom,
      },
      {
        add(data) {
          addRuleItem(form, props.path, data);
          onChange?.(form.getFieldsValue(true));
        },
        addGroup(defaultGroupData) {
          const mergedGroupData = defaultGroupData || { [RelationKey]: defaultRelationValue };
          addRuleGroup(form, props.path, ChildrenKey, mergedGroupData);
          onChange?.(form.getFieldsValue(true));
        },
        getGroupData() {
          return {
            [RelationKey]: form.getFieldValue(getRelationPath(props.path, RelationKey)),
            [ChildrenKey]: form.getFieldValue(props.path),
          };
        },
      },
      {
        index: props.name || 0,
        count: props.data.length,
        deepth,
        overMaxCount,
        overMaxDeepth,
        disabled,
        levelPath,
      },
    ) || [addDom, addGroupDom];
  });

  const listName = useMemo(() => props.name === null ? ChildrenKey : [props.name, ChildrenKey], [props.name, ChildrenKey]);
  return (
    <div
      className={clsx(`${cls}-list`, {
        [`${cls}-list-empty`]: props.data.length === 0,
      })}
    >
      <FormList name={listName}>
        {
          (fields) => {
            return fields.map((field, index) => {
              const item = form.getFieldValue([...props.path, field.name]) || {} as DataType;

              const path = [...props.path, field.name];
              // 处理rule group的情况
              if (item[RelationKey] || item[ChildrenKey]) {
                return (
                  <RuleItem overMaxCount={overMaxCount} key={field.key} isLeaf={false} path={props.path} index={index}>
                    <RuleNode<T> name={field.name} path={path} />
                  </RuleItem>
                );
              }

              // 处理children为function的情况
              if (typeof children === 'function') {
                return (
                  <RuleItem overMaxCount={overMaxCount} key={field.key} isLeaf path={props.path} index={index}>
                    {
                      children(
                        {
                          key: field.key + '',
                          name: field.name,
                        },
                        index,
                        {
                          getCurrentRowData() {
                            return form.getFieldValue([...props.path, index]) || {};
                          },
                          setCurrentRowData(value = {}) {
                            const currentRowData = form.getFieldValue([...props.path, index]) || {};
                            form.setFieldValue([...props.path, index], {
                              ...currentRowData,
                              ...value,
                            });
                            onChange?.(form.getFieldsValue(true));
                          },
                          getGroupData() {
                            return {
                              [RelationKey]: form.getFieldValue(getRelationPath(props.path, RelationKey)),
                              [ChildrenKey]: form.getFieldValue(props.path),
                            };
                          },
                        },
                      )
                    }
                  </RuleItem>
                );
              }

              // 末级节点的情况，这里需要设置FormListContext来保证path正常
              return (
                <RuleItem overMaxCount={overMaxCount} key={field.key} isLeaf path={props.path} index={index}>
                  <FormListContext.Provider
                    value={{
                      name: [index],
                      listName: [...props.path, index],
                    }}
                  >
                    {children}
                  </FormListContext.Provider>
                </RuleItem>
              );
            });
          }
        }
      </FormList>
      {
        !!ctrlDoms.length && (
          <div className={`${cls}-item ${cls}-item-ctrl`}>
            <div className={`${cls}-item-create`}>
              <DropIndicator key={[...props.path, props.data.length].join('-')} index={props.data.length} levelPath={levelPath} overMaxCount={overMaxCount}>
                <div className={`${cls}-indicator`} />
              </DropIndicator>
              <Space>
                {ctrlDoms}
              </Space>
            </div>
          </div>
        )
      }
    </div>
  );
}

const MemoRuleList = memo(
  RuleListCore,
  (prev, next) => {
    const { children } = fieldNamesTreeMap.get(prev.uid) as Required<FieldNames>;
    return (
      prev.name === next.name &&
      prev.path.join('-') === next.path.join('-') &&
      prev.data.length === next.data.length &&
      prev.data.every((item: any, index) => {
        // 忽略子节点数据的差异，只对比当前层级
        if (children in item) {
          return true;
        }
        return item === next.data[index];
      })
    );
  },
) as typeof RuleListCore;

export default function RuleList<T>(props: {
  path: (string | number)[]
  name: number | null
}) {
  const { Form } = useOutterComponents();
  const { uid } = useContext(RuleTreePropsContext);

  return (
    <Form.Item noStyle shouldUpdate>
      {
        (form) => {
          return (
            <MemoRuleList<T> {...props} uid={uid} data={form.getFieldValue(props.path) as T[] || []} />
          );
        }
      }
    </Form.Item>
  );
}